﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Anaglyph Mode
    /// </summary>
    public enum AnaglyphMode
    {
        /// <summary>
        /// None Mode
        /// </summary>
        None,
        /// <summary>
        /// True Anaglyph mode
        /// </summary>
        True,
        /// <summary>
        /// Halfcolor Anaglyph mode
        /// </summary>
        HalfColor,
        /// <summary>
        /// Grayscale Anaglyph mode
        /// </summary>
        Gray,
        /// <summary>
        /// Color Anaglyph mode
        /// </summary>
        Color,
        /// <summary>
        /// Optimized Anaglyph mode
        /// </summary>
        Optimized,
    }

    /// <summary>
    /// This filter takes two images (normally) and renders an anaglyph pic.
    /// Choose between 5 different modes which are all common
    /// </summary>
    public class Anaglyph : BaseImageFilter, ITwoSourceFilter
    {
        protected AnaglyphMode m_AnaglyphMode = AnaglyphMode.Optimized;

        /// <summary>
        /// Initializes a new instance of the Anayglyph class.
        /// </summary>
        public Anaglyph()
        {
        }

        /// <summary>
        /// Initializes a new instance of the Anayglyph class.
        /// </summary>
        /// <param name="_anaglyphMode"></param>
        public Anaglyph(AnaglyphMode _anaglyphMode)
        {
            m_AnaglyphMode = _anaglyphMode;
        }

        /// <summary>
        /// Initializes a new instance of the Anayglyph class.
        /// </summary>
        /// <param name="_anaglyph">The _anaglyph.</param>
        internal Anaglyph(Anaglyph _anaglyph)
        {
            m_AnaglyphMode = _anaglyph.m_AnaglyphMode;
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            return Process((UnsafeBitmap)_bitmap.Clone(), _bitmap);
        }

        /// <summary>
        /// Gets or sets the mode.
        /// </summary>
        /// <value>The mode.</value>
        public AnaglyphMode Mode
        {
            get { return m_AnaglyphMode; }
            set { m_AnaglyphMode = value; }
        }

        #region ITwoSourceFilter Members

        /// <summary>
        /// Processes the specified _BMP source left.
        /// </summary>
        /// <param name="_bmpSourceLeft">The _BMP source left.</param>
        /// <param name="_bmpSourceRight">The _BMP source right.</param>
        /// <returns></returns>
        public UnsafeBitmap Process(UnsafeBitmap _bmpSourceLeft, UnsafeBitmap _bmpSourceRight)
        {
            byte r1 = 0;
            byte g1 = 0;
            byte b1 = 0;
            byte r2 = 0;
            byte g2 = 0;
            byte b2 = 0;
            byte a = 0;
            double r = 0;
            double g = 0;
            double b = 0;

            int nHeight = _bmpSourceLeft.Height;
            int nWidth = _bmpSourceLeft.Width;
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmapResult = new UnsafeBitmap(_bmpSourceLeft.Width, _bmpSourceLeft.Height);

            switch (m_AnaglyphMode)
            {
                case AnaglyphMode.True:

                    for (y = 0; y < nHeight; y++)
                    {
                        for (x = 0; x < nWidth; x++)
                        {
                            _bmpSourceRight.GetPixelDirect(x, y, out a, out r1, out g1, out b1);
                            _bmpSourceRight.GetPixelDirect(x, y, out a, out r2, out g2, out b2);
                            r = r1 * 0.299 + g1 * 0.587 + b1 * 0.114;
                            g = 0;
                            b = r2 * 0.299 + g2 * 0.587 + b2 * 0.114;
                            bitmapResult.SetPixelDirect(x, y, (byte)r, (byte)g, (byte)b);
                        }
                    }
                    break;

                case AnaglyphMode.Color:
                    // for each line
                    Color color1 = Color.Transparent;
                    Color color2 = Color.Transparent;
                    for (y = 0; y < nHeight; y++)
                    {
                        // for each pixel
                        for (x = 0; x < nWidth; x++)
                        {
                            color1 = _bmpSourceLeft.GetPixel(x, y);
                            color2 = _bmpSourceRight.GetPixel(x, y);

                            // keep Red as it is and take only Green and Blue from the second image
                            _bmpSourceLeft.SetPixel(x, y, Color.FromArgb(color1.R, color2.G, color2.B));
                        }
                    }
                    break;

                case AnaglyphMode.HalfColor:
                    // for each line
                    for (y = 0; y < nHeight; y++)
                    {
                        // for each pixel
                        for (x = 0; x < nWidth; x++)
                        {
                            _bmpSourceLeft.GetPixelDirect(x, y, out a, out r1, out g1, out b1);
                            _bmpSourceRight.GetPixelDirect(x, y, out a, out r2, out g2, out b2);
                            r = (byte)r1 * 0.299 + g1 * 0.587 + b1 * 0.114;
                            g1 = g2;
                            b1 = b2;
                            bitmapResult.SetPixelDirect(x, y, (byte)r, (byte)g, (byte)b);
                        }
                    }
                    break;

                case AnaglyphMode.Optimized:
                default:
                    // for each line
                    for (y = 0; y < nHeight; y++)
                    {
                        // for each pixel
                        for (x = 0; x < nWidth; x++)
                        {
                            _bmpSourceLeft.GetPixelDirect(x, y, out a, out r1, out g1, out b1);
                            _bmpSourceRight.GetPixelDirect(x, y, out a, out r2, out g2, out b2);
                            r1 = (byte)(g1 * 0.7 + b1 * 0.3);
                            g1 = g2;
                            b1 = b2;

                            bitmapResult.SetPixelDirect(x, y, r1, g1, b1);
                        }
                    }
                    break;

                case AnaglyphMode.Gray:
                    // for each line
                    for (y = 0; y < nHeight; y++)
                    {
                        // for each pixel
                        for (x = 0; x < nWidth;x++)
                        {
                            _bmpSourceLeft.GetPixelDirect(x, y, out a, out r1, out g1, out b1);
                            _bmpSourceRight.GetPixelDirect(x, y, out a, out r2, out g2, out b2);
                            r1 = (byte)(r1 * 0.299 + g1 * 0.587 + b1 * 0.114);
                            g1 = (byte)(r2 * 0.299 + g2 * 0.587 + b2 * 0.114);
                            b1 = g1;
                            bitmapResult.SetPixelDirect(x, y, r1, g1, b1);
                        }
                    }
                    break;
            }
            return bitmapResult;
        }

        #endregion

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Anaglyph(this);
        }
    }
}
